// File Name: RotateClientSideCustomProvider.cpp

#pragma comment(lib, "comsuppw.lib")

#include <UIAutomation.h>
#include <UIAutomationCore.h>
#include <UIAutomationCoreApi.h>
#include <UIAutomationClient.h>
#include <comutil.h>
//#include <string.h>

#include "Stdafx.h"
#include "RotateClientSideCustomProvider.h"
#include "CustomProxyFactory.h"
#include "CustomUIAutomationCPP.h"

using namespace System;

namespace UIAutomationCPP
{
	RotateClientSideCustomProvider::RotateClientSideCustomProvider()
	{
		rotateValue = 0;
		refCount = 1;

		InitIds();
		InsertProxy();
	}

	RotateClientSideCustomProvider::RotateClientSideCustomProvider(HWND owner)
	{
		rotateValue = 0;
		controlHWnd = owner;
		refCount = 1;

		InitIds();
		InsertProxy();
	}

	RotateClientSideCustomProvider::~RotateClientSideCustomProvider()
	{
		delete [] factory;
		delete [] entry;
	}

	RotateClientSideCustomProvider& RotateClientSideCustomProvider::operator =(RotateClientSideCustomProvider& rhs)
	{
		if(this != &rhs)
			return rhs;
		return *this;
	}

	void RotateClientSideCustomProvider::InsertProxy()
	{
		LPCWSTR className = L"CustomUIAutomationCPP";
		BSTR name;
		IUIAutomation* pAutomation;

		//HRESULT hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
		CoInitialize(NULL);
		//		hr = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER || CLSCTX_ALL, __uuidof(IUIAutomation), (void **)&uia);
		HRESULT hr = CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, (void**)&pAutomation);
		if(FAILED(hr))
			return;

		hr = (*pAutomation).get_ProxyFactoryMapping(&pMap);
		/*if(FAILED(hr))
			return;*/
		if(hr == E_INVALIDARG)
			return;

		// Instantiate the proxy factory.
		factory = new CustomProxyFactory();
		// Make an entry with the factory.
		hr = (*pAutomation).CreateProxyFactoryEntry(factory, &entry);
		if(FAILED(hr))
			return;

		name = SysAllocString(className);
		(*entry).put_ClassName(className);
		(*entry).put_ImageName(NULL);
		(*entry).put_AllowSubstringMatch(TRUE);
		
		get_ProxyTable(pAutomation);
		(*pAutomation).Release();
		SysFreeString(name);
		CoUninitialize();
	}

	void RotateClientSideCustomProvider::get_ProxyTable(IUIAutomation* pAutomation)
	{
		UINT count;
		BSTR className;
		//BSTR imageName;

		HRESULT hr = (*pAutomation).get_ProxyFactoryMapping(&pMap);
		if (SUCCEEDED(hr))
		{
			if (SUCCEEDED((*pMap).get_Count(&count)))
			{
				for (UINT x = 0; x < count; x++)
				{
					if (SUCCEEDED((*pMap).GetEntry(x, &entry)))
					{
						(*entry).get_ClassName(&className);
						String^ location = gcnew String(className);
						String^ find = gcnew String("SysTreeView32");

						if (location == find)
						{
							// Insert the entry at the start of the mapping.
							(*pMap).InsertEntry(x, entry);
							SysFreeString(className);
							(*entry).Release();
							break;
						}
						/*if (SUCCEEDED((*entry).get_ImageName(&imageName)))
						{
							if (imageName)
							{
								SysFreeString(imageName);
							}
						}*/
					}
					(*entry).Release();
				}
			}
			(*pMap).Release();
		}
	}

	void RotateClientSideCustomProvider::InitIds()
	{
		static bool inited = false;
		if (!inited)
		{
			inited = true;
			Ids.ValueProperty = CustomUiaIdLookup(AutomationIdentifierType_Property, &valuePropertyGuid);
			Ids.IsReadOnlyProperty = CustomUiaIdLookup(AutomationIdentifierType_Property, &isReadOnlyPropertyGuid);
			Ids.RotatePattern = CustomUiaIdLookup(AutomationIdentifierType_Pattern, &patternGuid);
			Ids.CustomEvent = CustomUiaIdLookup(AutomationIdentifierType_Event, &eventGuid);
		}
	}

	int RotateClientSideCustomProvider::CustomUiaIdLookup(AutomationIdentifierType type, GUID* pGuid)
	{
		if(*pGuid == valuePropertyGuid)
			return Rotate_Value_PropertyID;
		else if(*pGuid == isReadOnlyPropertyGuid)
			return Rotate_IsReadOnly_PropertyID;
		else if(*pGuid == patternGuid)
			return Rotate_PatternID;
		else if(*pGuid == eventGuid)
			return Rotate_Reset_EventID;

		return 0;
	}

	STDMETHODIMP RotateClientSideCustomProvider::GetPropertyValue(PROPERTYID propertyId, VARIANT *pRetVal)
	{
		if (propertyId == Ids.ValueProperty)
		{
			pRetVal->vt = VT_BSTR;
			pRetVal->bstrVal = SysAllocString(L"RotateClientSideCustomProvider Control");
		}
		/*else if (propertyId == CustomIds.ControlTypeProperty)
		{
			pRetVal->vt = VT_I4;
			pRetVal->lVal = CustomIds.ButtonControlType;
		}*/
		else
		{
			pRetVal->vt = VT_EMPTY;
		   // UI Automation will attempt to get the property from the host window provider.
		}
		return S_OK;
	}

	STDMETHODIMP RotateClientSideCustomProvider::GetPatternProvider(PATTERNID patternId, IUnknown** pRetVal)
	{
		if(patternId == Ids.RotatePattern)
		{
			AddRef();
			*pRetVal = this;
		}
		else
			*pRetVal = NULL;

		return S_OK;
	}

	STDMETHODIMP RotateClientSideCustomProvider::get_HostRawElementProvider(IRawElementProviderSimple** pRetVal)
	{
		return UiaHostProviderFromHwnd(controlHWnd, pRetVal);
	}

	STDMETHODIMP RotateClientSideCustomProvider::get_ProviderOptions(ProviderOptions* pRetVal)
	{
		*pRetVal = ProviderOptions_ClientSideProvider;
		return S_OK;
	}

	STDMETHODIMP RotateClientSideCustomProvider::get_IsReadOnly(BOOL *pIsReadOnly)
	{
		*pIsReadOnly = FALSE;
		return S_OK;
	}

	STDMETHODIMP RotateClientSideCustomProvider::get_Value(BSTR *pValue)
	{
		*pValue = (BSTR)rotateValue;
		return S_OK;
	}

	STDMETHODIMP RotateClientSideCustomProvider::SetValue(LPCWSTR pNewValue)
	{
		rotateValue = pNewValue;
		return S_OK;
	}

	STDMETHODIMP RotateClientSideCustomProvider::Reset()
	{
		//RotatePatternClientWrapper::Reset()
		return S_OK;
	}

	HRESULT __stdcall RotateClientSideCustomProvider::QueryInterface(REFIID riid, void **ppvObj)
	{
		if(riid == IID_IUnknown)
			*ppvObj =(IUnknown*)((IRawElementProviderSimple*)this);
		else if(riid == IID_IRawElementProviderSimple)
			*ppvObj =(IRawElementProviderSimple*)this;
		else
		{
			*ppvObj = NULL;
			return E_NOINTERFACE;
		}

		((IUnknown*)(*ppvObj))->AddRef();
		return S_OK;
	}

	ULONG __stdcall RotateClientSideCustomProvider::AddRef()
	{
		InterlockedIncrement(&refCount);
		return refCount;
	}

	ULONG __stdcall RotateClientSideCustomProvider::Release()
	{
		ULONG ulRefCount = InterlockedDecrement(&refCount);
		if (ulRefCount == 0)
		{
			delete this;
		}
		return ulRefCount;
	}
}